﻿/*  Copyright 2012 PerceiveIT Limited
 *  This file is part of the Scryber library.
 *
 *  You can redistribute Scryber and/or modify 
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  Scryber is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Scryber source code in the COPYING.txt file.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;

namespace Scryber
{
    /// <summary>
    /// Defines the Licensing model for PDF components. 
    /// If you do modify, then you are legally obliged to release 
    /// that copy to the wider community and the original authors.
    /// </summary>
    public static class Licensing
    {
        private static object _lock;
        private static Dictionary<Type, PDFLicenseTerms> _knownlicenses;

        private static byte[] _enterpriseSignature;
        private static string _enterpriseName;
        private static DSACryptoServiceProvider _enterpriseProvider;

        static Licensing()
        {
            _lock = new object();
            _knownlicenses = new Dictionary<Type, PDFLicenseTerms>();
        }

        public static IPDFLicense GetLicense(Type t)
        {
            PDFLicenseTerms lic;
            string key;
            lock (_lock)
            {

                if (!_knownlicenses.TryGetValue(t, out lic))
                {
                    PDFLicenseLoader loader = PDFLicenseLoader.Create();
                    PDFLicense loaded = loader.GetLicenseKey(t);

                    object[] all = t.GetCustomAttributes(typeof(PDFLicensedComponentAttribute), true);

                    if (all == null || all.Length == 0)
                        throw new PDFLicenceException(string.Format(Errors.TypeIsNotRegisteredWithLicensedComponentAttribute, t.Name));

                    PDFLicensedComponentAttribute attr = (PDFLicensedComponentAttribute)all[0];
                    key = attr.PublicKey;
                    if (string.IsNullOrEmpty(key))
                        throw new PDFLicenceException(string.Format(Errors.TypeDoesNotHavePublicKeyForLicence, t.Name));

                    if (loaded.Exists == false)
                        lic = PDFLicenseTerms.NotFound(attr.Action, "No license was found for the product");
                    else
                    {
                        lic = PDFLicenseTerms.GenerateTerms(loaded, key);
                        string message;
                        if (lic.ValidateType(t, out message) == false)
                            lic = PDFLicenseTerms.InvalidType(attr.Action, message);
                    }
                    _knownlicenses.Add(t, lic);
                }
            }

            return lic;
        }

        /// <summary>
        /// Sets the enterprise token that matches any Enterprise license token value in these licenses.
        /// Only 1 enterprise token is allowed in any app domain
        /// </summary>
        /// <param name="token"></param>
        public static void SetEnterpriseLicense(string name, string signature, string publickey)
        {
            if (string.IsNullOrEmpty(name))
                throw new ArgumentNullException("name");

            if (string.IsNullOrEmpty(signature))
                throw new ArgumentNullException("signature");

            if (string.IsNullOrEmpty("publickey"))
                throw new ArgumentNullException("publickey");

            _enterpriseName = name;

            // setup the provider from the public key:
            DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
            dsa.FromXmlString(publickey);
            _enterpriseProvider = dsa;

            // set the signature data:
            _enterpriseSignature = Convert.FromBase64String(signature);

        }

        /// <summary>
        /// Sets the license terms for a specific type provided as a string of xml data.
        /// Once set these terms contained in the license will be used for that type for the duration of the application domain.
        /// </summary>
        /// <param name="t">The type this license applies to</param>
        /// <param name="terms">The terms as a string of encrypted XML data</param>
        public static void SetLicense(Type t, string terms)
        {
            using (System.IO.StringReader sr = new System.IO.StringReader(terms))
            {
                PDFLicense lic = PDFLicense.Load(sr, t);
                SetLicense(t, lic);
            }

        }

        /// <summary>
        /// Sets the license terms for a specific type provided as a stream of xml data.
        /// Once set these terms contained in the license will be used for that type for the duration of the application domain.
        /// </summary>
        /// <param name="t">The type this license applies to</param>
        /// <param name="terms">The terms as a stream of encrypted XML data</param>
        public static void SetLicense(Type t, System.IO.Stream terms)
        {
            PDFLicense lic = PDFLicense.Load(terms, t);
            SetLicense(t, lic);
        }

        /// <summary>
        /// Sets the license terms for a specific type.
        /// Once set these terms contained in the license will be used for that type for the duration of the application domain.
        /// </summary>
        /// <param name="t"></param>
        /// <param name="license"></param>
        public static void SetLicense(Type t, PDFLicense license)
        {
            if (null == license)
                throw new ArgumentNullException("license");
            if (null == t)
                throw new ArgumentNullException("t");

            lock (_lock)
            {
                if (_knownlicenses.ContainsKey(t) == false)
                {
                    object[] all = t.GetCustomAttributes(typeof(PDFLicensedComponentAttribute), true);

                    if (all == null || all.Length == 0)
                        throw new PDFLicenceException(string.Format(Errors.TypeIsNotRegisteredWithLicensedComponentAttribute, t.Name));

                    PDFLicensedComponentAttribute attr = (PDFLicensedComponentAttribute)all[0];
                    string key = attr.PublicKey;
                    if (string.IsNullOrEmpty(key))
                        throw new PDFLicenceException(string.Format(Errors.TypeDoesNotHavePublicKeyForLicence, t.Name));

                    PDFLicenseTerms lic = PDFLicenseTerms.GenerateTerms(license, key);

                    string message;
                    if (lic.ValidateType(t, out message) == false)
                        lic = PDFLicenseTerms.InvalidType(attr.Action, message);


                    _knownlicenses[t] = lic;

                }
            }
        }


        #region public sealed class PDFLicense : System.Xml.Serialization.IXmlSerializable

        /// <summary>
        /// A single component licence that contains the encrypted data 
        /// validating the license terms and a signature that validates the terms
        /// </summary>
        [Serializable()]
        public sealed class PDFLicense : System.Xml.Serialization.IXmlSerializable
        {
            #region public string Terms {get;set;}

            private string _terms;
            /// <summary>
            /// The license terms encoded as a base 64 string.
            /// </summary>
            public string Terms { get { return _terms; } set { _terms = value; } }

            #endregion

            #region pubic string Signature { get;set;}

            private string _sig;

            /// <summary>
            /// The signature of the terms encoded as a base64 string
            /// </summary>
            public string Signature { get { return _sig; } set { _sig = value; } }

            #endregion

            #region public bool Exists {get;set;}

            [NonSerialized()]
            private bool _exists = false;

            /// <summary>
            /// Gets or sets the flag that states if the licence exisits or not
            /// </summary>
            public bool Exists
            {
                get { return _exists; }
                private set { _exists = value; }
            }

            #endregion

            public PDFLicense(string terms, string signature)
            {
                this._terms = terms;
                this._sig = signature;
            }

            private PDFLicense()
            {
            }


            public void Save(System.IO.Stream stream)
            {
                try
                {
                    System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(PDFLicense));
                    ser.Serialize(stream, this);
                }
                catch (Exception ex)
                {
                    throw new PDFLicenceException(Errors.CannotSerializePDFLicenceToStream, ex);
                }
            }

            /// <summary>
            /// load a license from stream data.
            /// </summary>
            /// <param name="data"></param>
            /// <returns></returns>
            public static PDFLicense Load(System.IO.Stream data, Type t)
            {
                PDFLicense lic;
                try
                {
                    System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(PDFLicense));
                    object obj = ser.Deserialize(data);
                    lic = (PDFLicense)obj;
                    lic.Exists = true;
                }
                catch (Exception ex)
                {
                    throw new PDFLicenceException(string.Format(Errors.CannotDeserializePDFLicenceFromData, t), ex);
                }
                return lic;
            }

            /// <summary>
            /// load a license from text reader data.
            /// </summary>
            /// <param name="data"></param>
            /// <returns></returns>
            public static PDFLicense Load(System.IO.TextReader reader, Type t)
            {
                PDFLicense lic;
                try
                {
                    System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(PDFLicense));
                    object obj = ser.Deserialize(reader);
                    lic = (PDFLicense)obj;
                    lic.Exists = true;
                }
                catch (Exception ex)
                {
                    throw new PDFLicenceException(string.Format(Errors.CannotDeserializePDFLicenceFromData, t), ex);
                }
                return lic;
            }

            /// <summary>
            /// An empty non-existant licence
            /// </summary>
            /// <returns></returns>
            internal static PDFLicense EmptyLicence()
            {
                PDFLicense lic = new PDFLicense();
                lic.Exists = false;
                return lic;
            }

            public static PDFLicense Build(DateTime start, DateTime end, PDFLicenseType type, string[] licensedfor, string product,
                PDFLicenseAction action, Version min, Version max, string assmsig, string privateKey)
            {
                PDFLicenseTerms terms = new PDFLicenseTerms(start, end, type, licensedfor, product, action, min, max, assmsig);
                return Build(terms, privateKey);
            }

            private static PDFLicense Build(PDFLicenseTerms terms, string privateKey)
            {
                return terms.CreateLicense(privateKey);
            }



            #region IXmlSerializable implementation

            private const string LicenceElement = "Licence";
            private const string TermsElementName = "Terms";
            private const string SigElementName = "Sig";

            public System.Xml.Schema.XmlSchema GetSchema()
            {
                return null;
            }

            public void ReadXml(System.Xml.XmlReader reader)
            {
                while (reader.Read())
                {
                    if (reader.NodeType == System.Xml.XmlNodeType.Element)
                    {
                        if (reader.LocalName == TermsElementName)
                        {
                            reader.Read(); //advance to content
                            this.Terms = reader.ReadContentAsString();
                        }
                        else if (reader.LocalName == SigElementName)
                        {
                            reader.Read();
                            this.Signature = reader.ReadContentAsString();
                        }
                    }
                }
                if (string.IsNullOrEmpty(this.Signature))
                    throw new NullReferenceException("No Signature data found in license");
                if (string.IsNullOrEmpty(this.Terms))
                    throw new NullReferenceException("No Terms data found in license");

            }

            public void WriteXml(System.Xml.XmlWriter writer)
            {
                writer.WriteStartElement(LicenceElement);
                writer.WriteStartElement(TermsElementName);
                writer.WriteString(this.Terms);
                writer.WriteEndElement();
                writer.WriteStartElement(SigElementName);
                writer.WriteString(this.Signature);
                writer.WriteEndElement();
                writer.WriteEndElement();
            }

            #endregion
        }

        #endregion

        #region private sealed class PDFLicenseTerms

        /// <summary>
        /// Defines the terms of a license that can be used to validate that a product is
        /// 1. licensed and 2. what to do if it's not valid
        /// </summary>
        private sealed class PDFLicenseTerms : IPDFLicense
        {
            private DateTime _start;
            private DateTime _end;
            private PDFLicenseType _type;
            private string[] _licensefor;
            private string _product;
            private PDFLicenseAction _action;
            private Version _min;
            private Version _max;
            private string _assmsig;
            private bool _isinvalid;
            private string _lastknownent;
            private string _invalidmesage;

            public PDFLicenseTerms(DateTime start, DateTime end, PDFLicenseType type, string[] licensedfor, string product,
                PDFLicenseAction action, Version min, Version max, string assmsig)
                : this()
            {
                this._start = start;
                this._end = end;
                this._type = type;
                this._product = product;
                this._action = action;
                this._min = min;
                this._max = max;
                this._assmsig = assmsig;
                if (this._type == PDFLicenseType.Global)
                {
                    this._licensefor = new string[] { GlobalLicenseName };
                }
                else
                {
                    this.ValidateLicenceForValues(licensedfor);
                    this._licensefor = licensedfor;
                }

            }

            private PDFLicenseTerms()
            {
            }

            PDFLicenseAction IPDFLicense.Validate(out string message)
            {
                return this.ValidateTerms(out message);
            }

            internal bool ValidateType(Type product, out string message)
            {
                System.Reflection.Assembly assm = product.Assembly;
                System.Reflection.AssemblyName name = assm.GetName();
                bool valid = true;
                message = string.Empty;

                if (string.Equals(name.Name, _product) == false)
                {
                    valid = false;
                    message = "This license does not correspond to the required product";
                }
                else if (name.Version.Minor < _min.Major || (name.Version.Major == _min.Major && name.Version.Minor < _max.Minor))
                {
                    valid = false;
                    message = "This license is not valid for the product version. Min version : " + _min.ToString() + ", Current assembly version : " + name.Version.ToString();
                }
                else if (name.Version.Major > _max.Major || (name.Version.Major == _max.Major && name.Version.Minor > _max.Minor))
                {
                    valid = false;
                    message = "This license is not valid for the product version. Min version : " + _min.ToString() + ", Current assembly version : " + name.Version.ToString();
                }
                else
                {
                    if (!string.IsNullOrEmpty(this._assmsig))
                    {
                        string currAssmSig = GetHexFromByteArray(name.GetPublicKeyToken());
                        if (!string.Equals(currAssmSig, _assmsig, StringComparison.OrdinalIgnoreCase))
                        {
                            valid = false;
                            message = "This license is for an assembly with a different strong name key";
                        }
                    }
                }
                return valid;
            }

            private static string GetHexFromByteArray(byte[] data)
            {
                StringBuilder sb = new StringBuilder();
                string hexAlphabet = "0123456789abcdef";
                if (data != null)
                {
                    foreach (byte b in data)
                    {
                        sb.Append(hexAlphabet[(int)(b >> 4)]);
                        sb.Append(hexAlphabet[(int)(b & 0xF)]);
                    }
                }
                return sb.ToString();
            }




            /// <summary>
            /// Ensures that the current components
            /// </summary>
            /// <param name="message"></param>
            /// <returns></returns>
            public PDFLicenseAction ValidateTerms(out string message)
            {
                //Previously checked the type and we know we are invalid
                if (_isinvalid)
                {
                    message = this._invalidmesage;
                    return this._action;
                }

                message = string.Empty;
                bool valid = true;

                DateTime now = DateTime.Now;
                if (now < _start)
                {
                    valid = false;
                    message = "The license is not yet active";
                }
                else if (now > _end)
                {
                    valid = false;
                    message = "The license has expired";
                }
                else if (_type == PDFLicenseType.Global)
                {
                    if (_licensefor.Length != 1 || string.Equals(_licensefor[0], GlobalLicenseName) == false)
                    {
                        valid = false;
                        message = "This global license is invalid";
                    }
                }
                else if (_type == PDFLicenseType.WebDomain)
                {
                    System.Web.HttpContext context = System.Web.HttpContext.Current;
                    if (null == context)
                    {
                        valid = false;
                        message = "This license is only valid for web applications";
                    }
                    else
                    {
                        string url = context.Request.Url.Host;
                        bool found = false;
                        foreach (string dns in _licensefor)
                        {
                            if (string.Equals(dns, url, StringComparison.OrdinalIgnoreCase))
                            {
                                found = true;
                                break;
                            }
                        }

                        if (!found)
                        {
                            valid = false;
                            message = "This license is not valid for the request domain";
                        }
                    }
                }
                else if (_type == PDFLicenseType.EnterpriseDomain)
                {
                    if (null == _enterpriseProvider || null == _enterpriseSignature || null == _enterpriseName)
                    {
                        valid = false;
                        message = "The enterprise license values have not been set on this app domain";
                    }
                    else
                    {
                        string enterprise = _enterpriseName;

                        bool found = false;

                        foreach (string allow in _licensefor)
                        {
                            if (null != _lastknownent && _lastknownent == allow)
                            {
                                found = true;
                                break;
                            }
                            else
                            {
                                byte[] name = Convert.FromBase64String(allow);

                                if (_enterpriseProvider.VerifyData(name, _enterpriseSignature))
                                {
                                    _lastknownent = allow;
                                    found = true;
                                    break;
                                }
                            }
                        }


                        if (!found)
                        {
                            valid = false;
                            message = "This license is not valid for the current enterprise";
                        }


                    }
                }
                else if (_type == PDFLicenseType.Machine)
                {
                    string machine = System.Environment.MachineName;
                    bool found = false;

                    foreach (string licensed in _licensefor)
                    {
                        if (string.Equals(machine, licensed, StringComparison.OrdinalIgnoreCase))
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        valid = false;
                        message = "This license is not valid for this machine.";
                    }
                }
                else if (_type == PDFLicenseType.User)
                {
                    string user = System.Environment.UserName;
                    bool found = false;

                    foreach (string licensed in _licensefor)
                    {
                        if (string.Equals(user, licensed, StringComparison.OrdinalIgnoreCase))
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        valid = false;
                        message = "This license is not valid for the current user.";
                    }
                }


                if (!valid)
                    return _action;
                else
                    return PDFLicenseAction.None;

            }

            public static PDFLicenseTerms GenerateTerms(PDFLicense lic, string publickey)
            {

                DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
                // setup the provider from the public key:
                dsa.FromXmlString(publickey);

                // get the license terms data:
                byte[] terms = Convert.FromBase64String(lic.Terms);

                // get the signature data:
                byte[] signature = Convert.FromBase64String(lic.Signature);

                if (dsa.VerifyData(terms, signature))
                {
                    PDFLicenseTerms valid = PDFLicenseTerms.Deserialize(terms);
                    return valid;
                }
                else
                    throw new PDFLicenceException(Errors.LicenseSignatureCouldNotBeValidated);

            }

            internal static PDFLicenseTerms InvalidType(PDFLicenseAction action, string message)
            {
                PDFLicenseTerms terms = new PDFLicenseTerms();
                terms._action = action;
                terms._invalidmesage = message;
                terms._isinvalid = true;
                return terms;
            }

            internal static PDFLicenseTerms NotFound(PDFLicenseAction action, string message)
            {
                PDFLicenseTerms terms = new PDFLicenseTerms();
                terms._action = action;
                terms._invalidmesage = message;
                terms._isinvalid = true;
                return terms;
            }


            public PDFLicense CreateLicense(string privateKey)
            {
                byte[] term = this.Serialize();
                DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
                dsa.FromXmlString(privateKey);

                byte[] sig = dsa.SignData(term);
                string termStr = Convert.ToBase64String(term);
                string sigStr = Convert.ToBase64String(sig);

                return new PDFLicense(termStr, sigStr);
            }

            private const char FieldSeparatorChar = '#';
            private const string DateTimeFormat = "yyyyMMdd";
            private const char NameSeparatorChar = '|';
            private const string GlobalLicenseName = "[GLOBAL]";
            private static System.Text.Encoding Encoding = System.Text.Encoding.UTF8;
            private const int VersionFieldCount = 2; //major.minor

            private static PDFLicenseTerms Deserialize(byte[] termsdata)
            {
                PDFLicenseTerms terms = null;

                try
                {
                    string full = Encoding.GetString(termsdata);

                    if (full.StartsWith(FieldSeparatorChar.ToString()) == false)
                        throw new ArgumentException("The format of the licence terms was not recognised.");

                    full = full.Substring(1);
                    string[] all = full.Split(FieldSeparatorChar);

                    terms = new PDFLicenseTerms();
                    int index = 0;
                    terms._start = DateTime.ParseExact(all[index++], DateTimeFormat, null);
                    terms._end = DateTime.ParseExact(all[index++], DateTimeFormat, null);
                    terms._type = (PDFLicenseType)Enum.Parse(typeof(PDFLicenseType), all[index++]);
                    string licenced = all[index++];
                    if (licenced.IndexOf(NameSeparatorChar) > -1)
                        terms._licensefor = licenced.Split(NameSeparatorChar);
                    else
                        terms._licensefor = new string[] { licenced };
                    terms._product = all[index++];
                    terms._action = (PDFLicenseAction)Enum.Parse(typeof(PDFLicenseAction), all[index++]);
                    terms._min = new Version(all[index++]);
                    terms._max = new Version(all[index++]);

                    //optional assembly signature
                    if (all.Length > index)
                        terms._assmsig = all[index];
                }
                catch (Exception ex)
                {
                    throw new PDFLicenceException(Errors.CouldNotDeserializeTheLicenseTerms, ex);
                }
                finally
                {

                }
                return terms;

            }

            private byte[] Serialize()
            {
                if (this._type == PDFLicenseType.Global)
                {
                    this._licensefor = new string[] { GlobalLicenseName };
                }
                else
                    this.ValidateLicenceForValues(_licensefor);

                StringBuilder sb = new StringBuilder();

                sb.Append(FieldSeparatorChar);
                sb.Append(this._start.ToString(DateTimeFormat));

                sb.Append(FieldSeparatorChar);
                sb.Append(this._end.ToString(DateTimeFormat));

                sb.Append(FieldSeparatorChar);
                sb.Append(this._type.ToString());

                sb.Append(FieldSeparatorChar);
                if (_licensefor.Length == 1)
                    sb.Append(this._licensefor[0]);
                else
                    sb.Append(string.Join(NameSeparatorChar.ToString(), this._licensefor));

                sb.Append(FieldSeparatorChar);
                sb.Append(this._product);

                sb.Append(FieldSeparatorChar);
                sb.Append(this._action.ToString());

                sb.Append(FieldSeparatorChar);
                sb.Append(this._min.ToString(VersionFieldCount));

                sb.Append(FieldSeparatorChar);
                sb.Append(this._max.ToString(VersionFieldCount));

                if (!string.IsNullOrEmpty(this._assmsig))
                {
                    sb.Append(FieldSeparatorChar);
                    sb.Append(this._assmsig);
                }
                string full = sb.ToString();
                return Encoding.GetBytes(full);

            }

            private void ValidateLicenceForValues(string[] names)
            {
                if (null == names || names.Length == 0)
                    throw new NullReferenceException("The licence for names cannot be empty or null");
                for (int i = 0; i < names.Length; i++)
                {
                    string name = names[i];
                    if (string.IsNullOrEmpty(name))
                        throw new NullReferenceException("The licence for names cannot be empty or null");
                    else if (name.IndexOf(NameSeparatorChar) > -1)
                        throw new ArgumentOutOfRangeException("names", "License for names cannot contain the '" + NameSeparatorChar.ToString() + "' character.");
                }

            }


        }


        #endregion

        public const string LicenceFileExtension = ".lic";

        #region private abstract class PDFLicenseLoader

        /// <summary>
        /// Base class for loading license files
        /// </summary>
        private abstract class PDFLicenseLoader
        {


            internal static PDFLicenseLoader Create()
            {
                if (System.Web.HttpContext.Current != null)
                    return new PDFWebLicenseLoader();
                else
                    return new PDFApplicationLicenseLoader();
            }

            internal PDFLicense GetLicenseKey(Type t)
            {
                PDFLicense lic;
                try
                {
                    lic = DoGetLicenseKey(t);
                }
                catch (PDFLicenceException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    throw new PDFLicenceException(string.Format(Errors.CouldNotLoadLicenceKey, t), ex);
                }
                return lic;
            }

            protected abstract PDFLicense DoGetLicenseKey(Type type);

            protected PDFLicense GetLicenseKeyFromFile(string path, Type type)
            {
                if (!System.IO.File.Exists(path))
                    return PDFLicense.EmptyLicence();
                else
                {
                    using (System.IO.FileStream fs = new System.IO.FileStream(path, System.IO.FileMode.Open))
                    {
                        return PDFLicense.Load(fs, type);
                    }
                }
            }
        }

        #endregion

        #region private class PDFWebLicenseLoader : PDFLicenseLoader

        /// <summary>
        /// License loader that looks in the bin directory of the local web server
        /// </summary>
        private class PDFWebLicenseLoader : PDFLicenseLoader
        {
            protected override PDFLicense DoGetLicenseKey(Type type)
            {
                System.Reflection.Assembly assm = type.Assembly;
                string name = assm.GetName().Name;
                string file = System.Web.HttpContext.Current.Server.MapPath("~/bin/" + name + LicenceFileExtension);

                return this.GetLicenseKeyFromFile(file, type);
            }
        }

        #endregion

        #region private class PDFApplicationLicenseLoader : PDFLicenseLoader

        /// <summary>
        /// License loader that looks in the executble directory of the currently running application
        /// </summary>
        private class PDFApplicationLicenseLoader : PDFLicenseLoader
        {

            protected override PDFLicense DoGetLicenseKey(Type type)
            {

                System.Reflection.Assembly assm = type.Assembly;
                string name = assm.GetName().Name;
                string file;
                System.Reflection.Assembly root;
                root = System.Reflection.Assembly.GetEntryAssembly();
                if (null == assm)
                    root = type.Assembly;
                file = assm.Location;
                file = System.IO.Path.GetDirectoryName(file) + System.IO.Path.DirectorySeparatorChar.ToString() + name + LicenceFileExtension;

                return this.GetLicenseKeyFromFile(file, type);
            }
        }

        #endregion

    }
}
